package com.yuns.config;

import com.yuns.jwt.JWTFilter;
import com.yuns.shiro.MyShiroRealm;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
@Slf4j
public class ShiroConfiguration {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout}")
    private int timeout;


    @Value("${spring.redis.password}")
    private String password;

    //Filter工厂，设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean factory(SecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JWTFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
//        shiroFilterFactoryBean.setSecurityManager(securityManager);
//        shiroFilterFactoryBean.setUnauthorizedUrl("/401");
        Map<String,String> map = new LinkedHashMap<>();
        // 所有请求通过我们自己的JWT Filter
        // 访问401和404页面不通过我们的Filter
        // 配置不会被拦截的链接 顺序判断
        map.put("/course/**", "anon");
        map.put("/course/*/*", "anon");
        map.put("/courseWatchRecord/**", "anon");
        map.put("/courseInfo/**", "anon");
        map.put("/liveInfo/**", "anon");
        map.put("/infoContentE/**", "anon");
        map.put("/companyUserBase/**", "anon");
        map.put("/exam/*", "anon");
        map.put("/exam/*/*", "anon");
        map.put("/examRecord/*", "anon");
        map.put("/examRecord/*/*", "anon");
        map.put("/courseType/**", "anon");
        map.put("/live/*", "anon");
        map.put("/live/*/*", "anon");
        map.put("/companyUserRel/*/*", "anon");
        map.put("/study/*", "anon");
        map.put("/study/*/*", "anon");
        map.put("/companyInfoBase/*", "anon");
        map.put("/companyInfoBase/*/*", "anon");
        map.put("/liveComment/*", "anon");
        map.put("/liveComment/*/*", "anon");
        map.put("/courseNote/*", "anon");
        map.put("/courseNote/*/*", "anon");
        map.put("/studyWatchRecord/*", "anon");

        map.put("/center/*", "anon");
        map.put("/centerExamRecord/*", "anon");
        map.put("/centerIntegral/*", "anon");
        map.put("/centerLearn/*", "anon");
        map.put("/centerNote/*", "anon");
        map.put("/centerWarnEdu/*", "anon");
        map.put("/centerWrongTitle/*", "anon");

        map.put("/statistic/*", "anon");

        map.put("/companyUserIntegral/*", "anon");
        map.put("/companyUserIntegral/*/*", "anon");
        map.put("/infoDocI/*", "anon");
        map.put("/infoDocI/*/*", "anon");

        map.put("/infoContentE/*", "anon");
        map.put("/liveUserRel/*","anon");
        map.put("/liveUserRel/*/*","anon");

        map.put("/courseWatchRecord/*", "anon");
        map.put("/courseWatchRecord/*/*", "anon");

        map.put("/questionOption/*","anon");
        map.put("/questionOption/*/*","anon");


        map.put("/sysLogin/login", "anon"); //登录接口排除
        map.put("/sysLogin/logout", "anon"); //登出接口排除
        map.put("/sysLogin/register", "anon");//用户注册

        map.put("/sysUser/**", "anon");//用户注册
        map.put("/sysUser/accountLogin", "anon");//用户注册

        map.put("/actuator/**","anon");

        map.put("/", "anon");
        map.put("/doc.html", "anon");
        map.put("/**/*.js", "anon");
        map.put("/**/*.css", "anon");
        map.put("/**/*.html", "anon");
        map.put("/**/*.svg", "anon");
        map.put("/**/*.pdf", "anon");
        map.put("/**/*.jpg", "anon");
        map.put("/**/*.png", "anon");
        map.put("/**/*.ico", "anon");
        map.put("/rechargeRecord/orders", "anon");
        map.put("/rechargeRecord/getOpenId", "anon");
        map.put("/rechargeRecord/callback", "anon");
        map.put("/rechargeRecord/queryRechargeRecordByUser", "anon");
        map.put("/tbUser/findWaterUserByOpenId/*", "anon");
        map.put("/tbUser/bindWaterUserByOpenId", "anon");
        // update-begin--Author:sunjianlei Date:20190813 for：排除字体格式的后缀
        map.put("/**/*.ttf", "anon");
        map.put("/**/*.woff", "anon");
        // update-begin--Author:sunjianlei Date:20190813 for：排除字体格式的后缀

        map.put("/druid/**", "anon");
        map.put("/swagger-ui.html", "anon");
        map.put("/swagger**/**", "anon");
        map.put("/webjars/**", "anon");
        map.put("/swagger**", "anon");
        map.put("/v2/**", "anon");
        map.put("/smartTableRecording/insertSmartTableRecord", "anon");
        map.put("/Callback/NBDeviceInfoChange.aspx", "anon");
        map.put("/Callback/NBDataNotify.aspx", "anon");
        map.put("/sysUser/queryUserByuserNumber", "anon");
        map.put("/na/iocm/devNotify/v1.1.0/reportCmdExecResult", "anon");
        map.put("/**", "jwt");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        log.info("shiro config 加载完成 ! ==============");
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(this.myShiroRealm());
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(this.cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(this.sessionManager());
        return securityManager;
    }

    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm myShiroRealm = new MyShiroRealm();
//        myShiroRealm.setCredentialsMatcher(this.hashedCredentialsMatcher());
        return myShiroRealm;
    }

    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));

        return hashedCredentialsMatcher;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     * @return
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setExpire(1800);// 配置缓存过期时间
        redisManager.setTimeout(timeout);
         redisManager.setPassword(password);
        return redisManager;
    }
    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     * @return
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * shiro session的管理
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }
}

